package cn.lijiajia3515.cairo.auth.framework.security.web.configurers;

import cn.lijiajia3515.cairo.auth.framework.security.web.authentication.captcha.CaptchaVerifyFilter;
import cn.lijiajia3515.cairo.auth.framework.security.web.authentication.captcha.CaptchaFilter;
import cn.lijiajia3515.cairo.captcha.image.DelegatingImageCaptchaHandler;
import cn.lijiajia3515.cairo.captcha.image.ImageCaptchaHandler;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;

import java.time.Duration;
import java.util.Optional;

public class CaptchaConfigurer<H extends HttpSecurityBuilder<H>> extends AbstractHttpConfigurer<CaptchaConfigurer<H>, H> {
	/**
	 * 请求路径
	 */
	private RequestMatcher captchaRequestMatcher;


	/**
	 * 图形校验码处理器
	 */
	private ImageCaptchaHandler imageCaptchaHandler;

	/**
	 * 校验码宽度参数名称
	 */
	private String widthParameterName = "width";

	/**
	 * 校验码高度参数名称
	 */
	private String heightParameterName = "height";

	/**
	 * 校验码 有效期
	 */
	private Duration captchaExpire = Duration.ofMinutes(5);

	/**
	 * 校验码 属性名称
	 */
	private String captchaCodeAttributeName = "captcha_code";

	/**
	 * 校验码 过期时间 属性名称
	 */
	private String captchaExpireAttributeName = "captcha_expire";

	/**
	 * 需要验证的路径
	 */
	private RequestMatcher CaptchaVerifyRequestMatcher;

	/**
	 * 验证 校验码 渺茫 参数名称
	 */
	private String verifyCodeParameterName = "verify_code";

	public CaptchaConfigurer() {

	}

	public CaptchaConfigurer<H> captchaUrl(String captchaUrl) {
		this.captchaRequestMatcher = new AntPathRequestMatcher(captchaUrl, HttpMethod.GET.name());
		return this;
	}

	public CaptchaConfigurer<H> captchaRequestMatcher(RequestMatcher captchaRequestMatcher) {
		this.captchaRequestMatcher = captchaRequestMatcher;
		return this;
	}


	public CaptchaConfigurer<H> captchaWidthParameterName(String widthParameterName) {
		this.widthParameterName = widthParameterName;
		return this;
	}

	public CaptchaConfigurer<H> captchaHeightParameterName(String heightParameterName) {
		this.heightParameterName = heightParameterName;
		return this;
	}

	public CaptchaConfigurer<H> captchaExpire(Duration captchaExpire) {
		this.captchaExpire = captchaExpire;
		return this;
	}

	public CaptchaConfigurer<H> imageCaptchaHandler(ImageCaptchaHandler imageCaptchaHandler) {
		this.imageCaptchaHandler = imageCaptchaHandler;
		return this;
	}

	public CaptchaConfigurer<H> verifyCaptchaCodeRequestMatcher(RequestMatcher requestMatcher) {
		this.CaptchaVerifyRequestMatcher = requestMatcher;
		return this;
	}

	public CaptchaConfigurer<H> verifyCaptchaCodeParameterName(String captchaCodeVerifyParameterName) {
		this.verifyCodeParameterName = captchaCodeVerifyParameterName;
		return this;
	}

	@Override
	public void init(H builder) throws Exception {
		//if (this.permitAll) {
		//	PermitAllSupport.permitAll(builder, getCaptchaRequestMatcher());
		//}
	}

	@Override
	public void configure(H builder) throws Exception {
		builder.addFilterAfter(createCaptchaFilter(builder), LogoutFilter.class);
		builder.addFilterAfter(createCaptchaCodeVerifyFilter(builder), CaptchaFilter.class);
	}

	public CaptchaFilter createCaptchaFilter(H builder) {
		CaptchaFilter filter = new CaptchaFilter(getCaptchaRequestMatcher());
		Optional.ofNullable(getCaptchaCodeAttributeName()).ifPresent(filter::setVerifyCodeAttributeName);
		Optional.ofNullable(getCaptchaExpireAttributeName()).ifPresent(filter::setVerifyCodeExpireAttributeName);
		Optional.ofNullable(getHeightParameterName()).ifPresent(filter::setHeightParameterName);
		Optional.ofNullable(getWidthParameterName()).ifPresent(filter::setWidthParameterName);
		Optional.ofNullable(getHeightParameterName()).ifPresent(filter::setHeightParameterName);
		Optional.ofNullable(getImageCaptchaHandler()).ifPresent(filter::setImageCaptchaHandler);


		return filter;
	}

	public CaptchaVerifyFilter createCaptchaCodeVerifyFilter(H builder) {
		RequestMatcher captchaCodeVerifyRequestMatcher = getCaptchaVerifyRequestMatcher();
		CaptchaVerifyFilter filter = new CaptchaVerifyFilter(captchaCodeVerifyRequestMatcher);
		Optional.ofNullable(getCaptchaCodeAttributeName()).ifPresent(filter::setVerifyCodeAttributeName);
		Optional.ofNullable(getCaptchaExpireAttributeName()).ifPresent(filter::setVerifyCodeExpireAttributeName);
		Optional.ofNullable(getVerifyCodeParameterName()).ifPresent(filter::setVerifyCodeParameterName);
		return filter;
	}


	public RequestMatcher getCaptchaRequestMatcher() {
		return captchaRequestMatcher != null ? captchaRequestMatcher : new AntPathRequestMatcher("/captcha", HttpMethod.GET.name());
	}

	public ImageCaptchaHandler getImageCaptchaHandler() {
		return imageCaptchaHandler != null ? imageCaptchaHandler : new DelegatingImageCaptchaHandler();
	}

	public String getWidthParameterName() {
		return widthParameterName;
	}

	public String getHeightParameterName() {
		return heightParameterName;
	}

	public RequestMatcher getCaptchaVerifyRequestMatcher() {
		return CaptchaVerifyRequestMatcher != null ? CaptchaVerifyRequestMatcher : request -> false;
	}

	public String getCaptchaCodeAttributeName() {
		return captchaCodeAttributeName;
	}


	public String getCaptchaExpireAttributeName() {
		return captchaExpireAttributeName;
	}

	public String getVerifyCodeParameterName() {
		return verifyCodeParameterName;
	}

}
